package cn.jtool.dig.client.comm.virtual;

import cn.jtool.dig.client.comm.MessageExchange;
import cn.jtool.dig.client.comm.VirtualManager;
import cn.jtool.dig.common.model.Commands;
import cn.jtool.dig.common.model.Packet;
import cn.jtool.dig.common.model.PacketBody;
import cn.jtool.dig.common.model.PacketHeader;
import cn.jtool.dig.common.netty.SNGenerator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Getter
@Slf4j
@Component
@ChannelHandler.Sharable
public class VirtualConnHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        Long sessionId = ctx.channel().attr(VirtualAttrKey.SESSION_ID).get();
        if(Objects.isNull(sessionId)){
            log.warn("[virtual]连接激活, 链路未就绪, 请稍后");
            ctx.executor().schedule(() -> {
                    this.channelActive(ctx);
            }, 100, TimeUnit.MILLISECONDS);
        }
        log.info("[virtual]连接激活, 链路就绪, 通道ID: {}", sessionId);

        PacketHeader packetHeader = PacketHeader.builder()
                .command(Commands.COMMON_RESPONSE.getCode())
                .digId(0x00)
                .channelId(sessionId)
                .sn(SNGenerator.gen())
                .build();
        PacketBody body = new PacketBody();
        body.writeByte(Commands.CREATE_SESSION.getCode());
        body.writeWord(packetHeader.getSn());
        body.writeByte(0x00);

        MessageExchange.toReal(Packet.builder().header(packetHeader).body(body).build());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Long channelId = ctx.channel().attr(VirtualAttrKey.SESSION_ID).get();
        if(Objects.nonNull(channelId)){
            Packet closeSessionPacket = this.createCloseSessionPacket(channelId);
            MessageExchange.toReal(closeSessionPacket);
            VirtualManager.removeClient(channelId);
            log.info("[virtual]连接关闭, 链路已释放, 通道ID: {}", channelId);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("[virtual]连接异常, 远程地址: {}", ctx.channel().remoteAddress(), cause);
        this.channelActive(ctx);
    }

    private Packet createCloseSessionPacket(long channelId){
        PacketHeader header = new PacketHeader();
        header.setCommand(Commands.CLOSE_SESSION.getCode());
        header.setDigId(0x00);
        header.setChannelId(channelId);
        header.setSn(SNGenerator.gen());
        return Packet.builder().header(header).build();
    }

}
